/******************************************************************************************************
	@Name EDP Protocol Stack
	@Author ZZY~
	@Version Universal
	@Time 2018/7/30 22:15
	@Information Onenet平台的EDP协议栈精简版,但是需要根据CPU的大小端模式来修改宏定义,需要自行计算出登录信息的长度
							可以生成登录,上传,命令回复,心跳的数据包,可以注册命令,可以自动解析
							移植时主要要保证内存分配函数的设置正确
	@Platform 目前已经经过测试证明可移植的硬件平台有:	STC15F系列(大端模式)
																										STC12C5A60S2(大端模式)
																										STM32F103系列(小端模式)
																										Tensilica L106 ESP8266芯片处理器(小端模式)
******************************************************************************************************/
#ifndef __EDP_H__
#define __EDP_H__
#include <stdint.h>
/***********************************************************************************************************************
配置项
***********************************************************************************************************************/
#define LOGIN WAY_2//第二种登录方式
#define CMD_ID_LENTH 36//命令ID长度,默认36
#define CMD_RES 0//开关命令响应功能 1-打开 0-关闭
#define CMD_NOT_REGISIT_HANDLE 0//使用未找到命令时的处理函数 1-使用 0-不使用
#define Unknow_CMD_Handle CMD_err//设置命令未找到时的处理函数,如果 CMD_NOT_REGISIT_HANDLE 为0 则此项不起作用
#define STATIC_MEMORY 0//设置是否使用静态内存,如果使用静态内存,则使用者只能使用数据类型和少部分函数,因为其他的都是动态分配
/***********************************************************************************************************************
数据处理
***********************************************************************************************************************/
#define Data_convert_16(x) __REV16(x)//当机器为小端模式时使用此宏将16位数据进行大小端变换
#define Data_convert_32(x) __REV(x)//当机器为小端模式时使用此宏将32位数据进行大小端变换
//#define Data_convert_16(x) x//若机器本身就为大端,这样定义即可
//#define Data_convert_32(x) x//若机器本身就为大端,这样定义即可
#define pEDP(Type) EDP_##Type##_t*//定义数据包指针用的简化宏
#define EDP(Type) EDP_##Type##_t//定义数据包结构体用的简化宏
/***********************************************************************************************************************
基础信息
***********************************************************************************************************************/
#define WAY_1 1
#define WAY_2 2
#define MAX_CONNECT_TIME 55
/***********************************************************************************************************************
登录信息定义
***********************************************************************************************************************/
#define APIKEY "5eGXlZjqSoEZGH1eRd7WrRFbPnE="//APIKEY,登录方式1要定义
#define APIKEY_LENTH 28//APIKEY长度,登录方式1要定义

#define DeviceID "621232537"//设备ID,登录方式1要定义
#define DEVICE_ID_LENTH 9//设备ID长度,,登录方式1要定义

#define ProductID "367936"//产品ID,登录方式2要定义
#define PRODUCT_ID_LENTH 6//产品ID长度,登录方式2要定义

#define AuthInformation "14622"//鉴权信息,登录方式2要定义
#define AUTHINFO_LENTH 5//鉴权信息长度,登录方式2要定义

#define CONNECT_TIME 120//保持连接时间,如果没有定义此宏,将采用默认的五分钟(300)

#define CODE_LENTH 15//授权码长度
/***********************************************************************************************************************
内存分配方案
***********************************************************************************************************************/
#define EDP_malloc pvPortMalloc
#define EDP_free vPortFree
/***********************************************************************************************************************
EDP协议第一字节消息类型
***********************************************************************************************************************/
#define Login_request  						0x10					//连接请求
#define Login_response 						0x20					//服务器连接响应
#define Push_data_request        	0x30					//推送数据请求
#define Connect_close    					0x40					//关闭连接
#define Save_data_request   		  0x80					//储存数据请求
#define Save_response    					0x90					//服务器储存数据响应
#define Command_request						0xA0					//命令请求
#define Command_response					0xB0					//命令响应
#define Ping											0xC0					//心跳请求
#define Ping_response  						0xD0					//心跳响应
/***********************************************************************************************************************
EDP协议登录返回码
***********************************************************************************************************************/
#define	Success														0			//连接成功
#define	Protocol_error										1			//验证失败-协议错误
#define	Device_ID_error										2			//验证失败-设备ID鉴权失败
#define	Server_failure										3			//验证失败-服务器失败
#define	Product_ID_error									4			//验证失败-产品ID鉴权失败
#define	Unauthorized											5			//验证失败-未授权
#define	Invalid_authorization_code				6			//验证失败-授权码无效
#define	Activation_code_not_allocated			7			//激活失败-激活码未分配
#define	Device_has_been_activated 				8			//激活失败-该设备已被激活
#define	Already_Login 										9			//验证失败-重复发送连接请求包
/***********************************************************************************************************************
以下为数据结构体
***********************************************************************************************************************/
//typedef struct
//{
//	uint8_t* Pack;
//	uint32_t Pack_Lenth;
//}EDP_Pack;
#define Max(a,b) ((a>b)?(a):(b))
#define Min(a,b) ((a<b)?(a):(b))
#pragma pack(1)
#if (LOGIN == WAY_1)
//登录方式1结构
typedef struct
{
	uint8_t Message_Type;
	uint8_t Remain_Lenth;
	uint16_t Protocol_Lenth;
	char Protocol[3];
	uint8_t Protocol_Version;
	uint8_t Connect_Flag;
	uint16_t Connect_Time;
	uint16_t Device_ID_Lenth;
	char Device_ID[DEVICE_ID_LENTH];
	uint16_t ApiKey_Lenth;
	char ApiKey[APIKEY_LENTH];
}EDP_Login_t;
#endif
#if (LOGIN == WAY_2)
//登录方式2结构
typedef struct
{
	uint8_t Message_Type;
	#if (PRODUCT_ID_LENTH+AUTHINFO_LENTH+15 > 127)
	uint16_t Remain_Lenth;
	#else
	uint8_t Remain_Lenth;
	#endif
	uint16_t Protocol_Lenth;
	char Protocol[3];
	uint8_t Protocol_Version;
	uint8_t Connect_Flag;
	uint16_t Connect_Time;
	uint16_t Device_ID_Lenth;
	uint16_t Product_ID_Lenth;
	char Product_ID[PRODUCT_ID_LENTH];
	uint16_t AuthInfo_Lenth;
	char AuthInfo[AUTHINFO_LENTH];
}EDP_Login_t;
#endif
//连接响应结构
typedef struct
{
	uint8_t Message_Type;//消息类型
	uint8_t Remain_Lenth;//剩余长度
	uint8_t Auth_Code_Flag;//授权码标志
	uint8_t Respond_Code;//返回码
	char Auth_Code[CODE_LENTH];//授权码
}EDP_Login_Respond_t;
//连接关闭结构
typedef struct
{
	uint8_t Message_Type;//消息类型
	uint8_t Remain_Lenth;//剩余长度
	uint8_t Error_Code;//错误码
}EDP_Connect_Close_t;
//SaveData_Respond结构
typedef struct
{
	uint8_t Message_Type;//消息类型
	uint8_t Remain_Lenth;//剩余长度
	uint8_t Flag;//标志
	uint16_t Message_Number;//消息编号
	uint8_t Code;//指示
}EDP_SaveData_Respond_t;
//命令结构
typedef struct
{
	uint8_t Message_Type;//消息类型
	uint8_t Remain_Lenth;//剩余长度
	uint16_t CMD_ID_lenth;//命令ID长度
	uint8_t CMD_ID[CMD_ID_LENTH];//命令ID
	uint32_t CMD_lenth;//命令长度
	char CMD[1];//命令
}EDP_Command_t;
typedef struct
{
	uint8_t Message_Type;//消息类型
	uint8_t Remain_Lenth;//剩余长度
}EDP_Ping_t;
#pragma pack()
typedef enum
{
	JSON_Format_1 = 1,//{"datastreams":[{"id":"temperature","datapoints":[{"at":"2013-04-22 22:22:22","value":36.5}]}]}
	Bin_Hex,//无格式
	JSON_Format_2,//格式 {"Datastream_id":value}
	JSON_Format_3,//格式 {“Datastream_id”:{“Data Time”:value}}   {"temperature":{"2015-03-22 22:31:12":22.5}}
	Custom_String,//格式 (两个自定义分隔符)(Datastream_id)(value)
	Custom_String_With_Time,//格式 (两个自定义分隔符)(Datastream_id)(datetime)(value)或(Datastream_id)(value) 
	Float_With_Time//格式 (年,8)(月,8)(日,8)(时,8)(分,8)(秒,8) (数据点个数,16)(Datastream_id.16)(float数据,32)
}SaveData_Type_t;

typedef short cb_in;//回调函数的输入值类型
typedef struct
{
	const char* _CMD;//命令
	void (*Callback) (cb_in);//命令对应的回调函数
}CMD_Node;
/***********************************************************************************************************************
EDP函数
***********************************************************************************************************************/
uint32_t EDP_login(uint8_t **Pack);//返回登录包长度,同时数据写入Pack指针
uint8_t EDP_Get_Login_Info(uint8_t *Pack);//输入登录返回包,返回登录结果
uint32_t EDP_PushData(uint8_t **Pack,char* Dest,uint32_t Data_Lenth);//输入指针,推送目标和数据长度返回PushData包长度,同时数据写入Pack指针
uint8_t EDP_Get_Close_Info(uint8_t *Pack);//输入连接关闭包,返回连接关闭原因
uint32_t EDP_SaveData(uint8_t **Pack,char* Dest,uint16_t Number,SaveData_Type_t SaveData_Type,uint32_t Data_Lenth);//输入指针,转发目标,消息编号,数据格式和数据长度,返回SaveData包
uint8_t EDP_Get_SaveData_Info(uint8_t* Pack);//输入SaveData返回包,返回SaveData结果
uint8_t EDP_CMD_Handle(uint8_t *Pack);//输入命令请求包,自动处理命令,如果命令没有注册,则调用回调函数(此功能可选择是否开启)并且返回0
uint32_t EDP_CMD_Respond(uint8_t **Pack,char *Data,char *Res);//输入命令请求包或者UUID和返回内容(可不输入),返回命令响应包
#endif
